Source code for binarycpython.utils.population_extensions.argument_handling

"""
Main script to provide the argument handling class extensions
"""

# pylint: disable=E1101

import logging
import os
import sys
from logging import config

import str2bool

from binarycpython.utils.logging_functions import verbosity_level_dict


[docs]class argument_handling: """ Extension for the Population class containing the code for source-file sampling functions """ def __init__(self, **kwargs): """ Init function for the spacing_functions class """ return
[docs] def set(self, **kwargs) -> None: """ Function to set the values of the population. This is the preferred method to set values of functions, as it provides checks on the input. the bse_options will get populated with all the those that have a key that is present in the self.defaults the population_options will get updated with all the those that have a key that is present in the self.population_options If neither of above is met; the key and the value get stored in a custom_options dict. Args: via kwargs all the arguments are either set to binary_c parameters, population_options or custom_options (see above) """ ############### # Go over all the input for key, value in kwargs.items(): # match to hostname if appropriate value = self._match_arg_to_host(arg={key: value}) ############### # Filter out keys for the population_options if key in self.population_options.keys(): self.vb_warning( "adding: {}={} to population_options".format(key, value), ) # validate values self._validate_population_options(key, value) # Set values self.population_options[key] = value ########### # Handle some actions for specific key setting # Update config for loggers if key == "log_config_file": if value is not None: # check if file exists if os.path.isfile(value): config.fileConfig(value) self.logger = logging else: raise ValueError(f"File {value} does not exist.") # Unset the loggers if value is None: self.logger = None # Update verbosity if key == "verbosity": if self.logger is not None: self.logger.setLevel(verbosity_level_dict[value]) for handler in self.logger.handlers: handler.setLevel(verbosity_level_dict[value]) # Update logfile for logging if key == "log_file": if self.logger is not None: for handler in self.logger.handlers: if isinstance(handler, logging.FileHandler): handler.close() handler.baseFilename = os.path.abspath(value) ############### # Filter out keys for the bse_options elif key in self.defaults: self.vb_warning( "adding: {}={} to BSE_options".format(key, value), ) self.bse_options[key] = value ############### # Extra check to check if the key fits one of parameter names that end with %d elif self._check_key_is_special_param(key): self.vb_warning( "adding: {}={} to BSE_options by catching the %d".format( key, value ), ) self.bse_options[key] = value ############### # The of the keys go into a custom_options dict else: self.vb_warning( "<<<< Warning: Key does not match previously known parameter: \ adding: {}={} to custom_options >>>>".format( key, value ), ) self.custom_options[key] = value
def _validate_population_options(self, key, value): """ Function to handle validation of the arguments passed to the population options """ # validate self.validation_schema({key: value})
[docs] def parse_cmdline(self) -> None: """ Function to handle settings values via the command line in the form x=y, w=z, etc. Best to be called after all the .set(..) lines, and just before the .evolve() is called If you input any known parameter (i.e. contained in population_options, defaults/bse_options or custom_options), this function will attempt to convert the input from string (because everything is string) to the type of the value that option had before. The values of the bse_options are initially all strings, but after user input they can change to ints. The value of any new parameter (which will go to custom_options) will be a string. """ # get the cmd-line args in the form x=y cmdline_args = sys.argv[1:] if cmdline_args: self.vb_info( "Found cmdline args. Parsing them now", ) # Grab the input and split them up, while accepting only non-empty entries # cmdline_args = args self.population_options["_commandline_input"] = cmdline_args # expand args by hostname cmdline_args = self.expand_args_by_hostname(cmdline_args) # Make dict and fill it cmdline_dict = {} for cmdline_arg in cmdline_args: split = cmdline_arg.split("=") # Check if its actually a key-value pair separated by "=" if len(split) == 2: parameter = split[0] value = split[1] old_value_found = False # Find an old value if parameter in self.population_options: old_value = self.population_options[parameter] old_value_found = True elif parameter in self.custom_options: old_value = self.custom_options[parameter] old_value_found = True elif parameter in self.bse_options: old_value = self.bse_options[parameter] old_value_found = True elif parameter in self.defaults: # this will revert to a string type, always old_value = self.defaults[parameter] old_value_found = True # (attempt to) convert type if old_value_found: if old_value is not None: try: self.vb_debug( "Converting type of {} from {} to {}".format( parameter, type(value), type(old_value) ), ) try: if isinstance(old_value, bool): value = str2bool.str2bool(value) else: value = type(old_value)(value) self.vb_debug( "Success!", ) except Exception as e: self.vb_error( "Failed to convert {param} value with type {type}: old_value is '{old}', new value is '{new}', {e}".format( param=parameter, old=old_value, type=type(old_value), new=split[1], e=e, ) ) self.exit(code=1) except ValueError: # might be able to eval the parameter, e.g. # an expression like "2-1" can eval to "1" # which would be valid try: evaled = eval(value) value = type(old_value)(evaled) self.vb_debug( "Success! (evaled)", ) except ValueError: self.vb_warning( "Tried to convert the given parameter {}/value {} to its correct type {} (from old value {}). But that wasn't possible.".format( parameter, value, type(old_value), old_value ), ) # Add to dict self.vb_info( "setting {} = {} ".format(parameter, value), ) cmdline_dict[parameter] = value else: self.vb_error( "Error: I do not know how to process {}: cmdline args should be in the format x=y, yours appears not to be.".format( cmdline_arg ), ) self.exit(1) # unpack the dictionary into the setting function that handles where the values are set self.set(**cmdline_dict)
def _return_argline(self, parameter_dict=None): """ Function to create the string for the arg line from a parameter dict """ # if not parameter_dict: parameter_dict = self.bse_options argline = "binary_c " # Combine all the key value pairs into string for param_name in sorted(parameter_dict): argline += "{} {} ".format(param_name, parameter_dict[param_name]) argline = argline.strip() return argline def _check_key_is_special_param(self, param_key): """ Function to check if the given key is part of the special parameter list """ is_special_key = any( [ True if ( param_key.startswith(param[:-2]) and len(param[:-2]) < len(param_key) ) else False for param in self.special_params ] ) return is_special_key def _check_full_system_dict_keys(self, full_system_dict): """ Function to check the full system dict that will be turned in to a binary_c call """ for key in full_system_dict.keys(): if key not in self.available_keys: # Deal with special keys if not self._check_key_is_special_param(key): msg = "Error: Found a parameter unknown to binary_c: {}. Abort".format( key ) raise ValueError(msg)